home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-09-17 | 9.5 KB | 311 lines | [TEXT/MPS ] |
- //========================================================================================
- //
- // File: odfjpeg.cpp
- // Release Version: $ ODF 2 $
- //
- // Author: Mark Lanett
- //
- // Copyright: (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
- //
- //========================================================================================
- //
- // Reads a JPEG using the Independent JPEG Group's free JPEG library.
- // Returns an FW_CBitmap.
- // Note: the returned bitmap is 16-bit and is not dithered.
- //
- // 6/3/96 mlanett Checked in. Derived from example.c from the JPEG library.
- //
-
- #include "FWOS.hpp"
- #include "odfjpeg.h"
-
- #ifndef FWMEMMGR_H
- #include "FWMemMgr.h"
- #endif
-
- #ifndef FWRECSHP_H
- #include "FWRecShp.h"
- #endif
-
- // Why does everyone insist on defining boolean themselves?
- // Something wrong with "char" or "int" or "ijg_boolean"?
-
- #define boolean yet_another_conflicting_boolean_type
-
- extern "C" {
- #include "jinclude.h"
- #include "jpeglib.h"
- #include "jerror.h"
- }
-
- #include <setjmp.h>
- #include "SLASinks.xh"
-
- #pragma segment odfjpeg
-
- /*-----------------------------------------------------------------------------
- Prototypes
-
- -----------------------------------------------------------------------------*/
-
- extern "C" {
- void ODF_JPEG_DecodeRow (JOCTET* samples, int inbytes, Ptr base, int outbytes);
-
- // The following prototypes are necessary for compilers that treat pointers
- // to static methods of a class as different from extern "C" functions. [sfu]
-
- typedef void (*t_jpegemPtr)(j_common_ptr cinfo);
- typedef void (*t_jpegcm1Ptr)(jpeg_decompress_struct *);
- typedef int (*t_jpegcm2Ptr)(jpeg_decompress_struct *);
- typedef void (*t_jpegcm3Ptr)(jpeg_decompress_struct *, long);
- }
-
- /*-----------------------------------------------------------------------------
- Utilities
- -----------------------------------------------------------------------------*/
-
- class TempMacLockedPixels {
- public:
- FW_DECLARE_AUTO (TempMacLockedPixels)
- TempMacLockedPixels (PixMapHandle lockedPixMap);
- ~TempMacLockedPixels ();
- private:
- PixMapHandle fPixMap;
- };
-
- FW_DEFINE_AUTO (TempMacLockedPixels)
-
- TempMacLockedPixels::TempMacLockedPixels (PixMapHandle lockedPixMap)
- : fPixMap (lockedPixMap)
- {
- }
-
- TempMacLockedPixels::~TempMacLockedPixels ()
- {
- ::UnlockPixels (fPixMap);
- }
-
- /*-----------------------------------------------------------------------------
- ODF_JPEG_ErrorManager
- -----------------------------------------------------------------------------*/
-
- struct ODF_JPEG_ErrorManager: public jpeg_error_mgr {
- jmp_buf fExitBuffer;
- static void ErrorExit (j_common_ptr cinfo);
- };
-
- void ODF_JPEG_ErrorManager::ErrorExit (j_common_ptr cinfo)
- {
- ODF_JPEG_ErrorManager* self = (ODF_JPEG_ErrorManager*) cinfo->err;
- // (cinfo->err->output_message) (cinfo);
- longjmp (self->fExitBuffer, 1);
- }
-
- /*-----------------------------------------------------------------------------
- ODF_JPEG_SourceManager
- -----------------------------------------------------------------------------*/
-
- struct ODF_JPEG_SourceManager: public jpeg_source_mgr {
- FW_DECLARE_AUTO(ODF_JPEG_SourceManager)
- ODF_JPEG_SourceManager (Environment* ev, FW_OSink* sink, size_t bufferSize = 1000);
- ~ODF_JPEG_SourceManager ();
-
- static void InitSource (j_decompress_ptr cinfo);
- static boolean FillInputBuffer (j_decompress_ptr cinfo);
- static void SkipInputData (j_decompress_ptr cinfo, long num_bytes);
- static void TermSource (j_decompress_ptr cinfo);
- private:
- Environment* fEv;
- FW_OSink* fSink;
- size_t fBufferSize;
- JOCTET* fBuffer;
- FW_Boolean fStartOfFile;
- };
-
- FW_DEFINE_AUTO(ODF_JPEG_SourceManager)
-
- ODF_JPEG_SourceManager::ODF_JPEG_SourceManager (Environment* ev, FW_OSink* sink, size_t bufferSize)
- : fEv (ev)
- , fSink (sink)
- , fBufferSize (bufferSize)
- {
- fBuffer = (JOCTET*) FW_CMemoryManager::AllocateBlock (fBufferSize);
- }
-
- ODF_JPEG_SourceManager::~ODF_JPEG_SourceManager ()
- {
- FW_CMemoryManager::FreeBlock (fBuffer);
- }
-
- void ODF_JPEG_SourceManager::InitSource (j_decompress_ptr cinfo)
- {
- ODF_JPEG_SourceManager* self = (ODF_JPEG_SourceManager*) cinfo->src;
- self->fStartOfFile = true;
- }
-
- boolean ODF_JPEG_SourceManager::FillInputBuffer (j_decompress_ptr cinfo)
- {
- ODF_JPEG_SourceManager* self = (ODF_JPEG_SourceManager*) cinfo->src;
-
- size_t available = self->fSink->GetReadableBytes (self->fEv);
- if (available == 0) {
- // Is it an empty data set?
- if (self->fStartOfFile)
- ERREXIT (cinfo, JERR_INPUT_EMPTY);
- // If it's just a truncated dataset, terminate it (and return a warning?)
- WARNMS (cinfo, JWRN_JPEG_EOF);
- self->fBuffer[0] = 0xFF;
- self->fBuffer[1] = JPEG_EOI;
- available = 2;
- }
- else {
- if (self->fBufferSize < available)
- available = self->fBufferSize;
- self->fSink->Read (self->fEv, self->fBuffer, available);
- }
-
- self->next_input_byte = self->fBuffer;
- self->bytes_in_buffer = available;
- self->fStartOfFile = false;
-
- return true;
- }
-
- void ODF_JPEG_SourceManager::SkipInputData (j_decompress_ptr cinfo, long num_bytes)
- {
- ODF_JPEG_SourceManager* self = (ODF_JPEG_SourceManager*) cinfo->src;
-
- while (self->bytes_in_buffer < num_bytes) {
- num_bytes -= self->bytes_in_buffer;
- FillInputBuffer (cinfo);
- }
-
- self->next_input_byte += num_bytes;
- self->bytes_in_buffer -= num_bytes;
- }
-
- void ODF_JPEG_SourceManager::TermSource (j_decompress_ptr cinfo)
- {
- FW_UNUSED(cinfo);
- }
-
- /*-----------------------------------------------------------------------------
- ODF_JPEG_DecodeRow
- -----------------------------------------------------------------------------*/
-
- void ODF_JPEG_DecodeRow (JOCTET* samples, int inbytes, Ptr base, int outbytes)
- {
- /*
- Now that we have a row of samples, rewrite them into a 16-bit Mac pixmap.
- */
- while (3 <= inbytes && 2 <= outbytes) {
- // Input from samples
- JOCTET red = *samples++;
- JOCTET green = *samples++;
- JOCTET blue = *samples++;
- inbytes -= 3;
- // Output to pixmap
- unsigned short rgb16 = ((red >> 3) << 10) | ((green >> 3) << 5) | (blue >> 3);
- *((unsigned short*)base) = rgb16;
- base += 2;
- outbytes -= 2;
- }
- }
-
- /*-----------------------------------------------------------------------------
- ODF_JPEG_Read
- -----------------------------------------------------------------------------*/
-
- FW_CBitmap ODF_JPEG_Read (Environment* ev, FW_OSink* sink)
- {
- jpeg_decompress_struct cinfo;
- ODF_JPEG_ErrorManager jerr;
- ODF_JPEG_SourceManager src (ev, sink);
-
- // Initialize error handling first
- cinfo.err = jpeg_std_error (&jerr);
- jerr.error_exit = (t_jpegemPtr)ODF_JPEG_ErrorManager::ErrorExit;
- if (setjmp (jerr.fExitBuffer)) {
- jpeg_destroy_decompress (&cinfo);
- FW_Failure (FW_xReadableStream);
- }
-
- // Initialize rest of JPEG library
- jpeg_create_decompress (&cinfo);
- src.init_source = (t_jpegcm1Ptr)ODF_JPEG_SourceManager::InitSource;
- src.fill_input_buffer = (t_jpegcm2Ptr)ODF_JPEG_SourceManager::FillInputBuffer;
- src.skip_input_data = (t_jpegcm3Ptr)ODF_JPEG_SourceManager::SkipInputData;
- src.resync_to_restart = jpeg_resync_to_restart;
- src.term_source = (t_jpegcm1Ptr)ODF_JPEG_SourceManager::TermSource;
- src.bytes_in_buffer = 0;
- src.next_input_byte = nil;
- cinfo.src = &src;
-
- // Calling C++ code (FW_OSink, FW_CBitmap, etc) can result in exceptions being
- // thrown. Must protect the jpeg_decompress_struct from not being
- // deleted properly. An alternative way to do that would be to subclass
- // it and give it a destructor (and make it an AUTO(destruct) object).
- FW_CBitmap bitmap;
-
- FW_TRY {
-
- // Start reading data
- jpeg_read_header (&cinfo, TRUE);
- jpeg_start_decompress (&cinfo);
-
- // Ok, now we have anything we could possibly need (including the colormap if
- // we asked for color quantization).
- // (1) Create the ODF bitmap object (16-bits deep)
- // (2) Create a work buffer (using the jpeglib's auto-deleting memory manager)
- bitmap = FW_CBitmap (cinfo.output_width, cinfo.output_height, 16);
- //.ChangeBitmap (cinfo.output_width, cinfo.output_height, 16, false);
- if (0) // XXX we don't really need to do this
- {
- // Erase the bitmap; use nested scope to avoid context lifetime/thread
- // problems. That is, if I didn't use a nested scope then the context (bc)
- // would stay alive until the end of this function. Since we will be
- // yielding to other threads during the call to jpeg_read_scanlines below,
- // other threads could create contexts as well. The ODF graphics layer is
- // not thread-safe and can't deal with contexts in multiple threads, so we
- // must force this context to be destroyed ASAP.
-
- FW_CBitmapContext bc (ev, bitmap);
- FW_CMapping mapping (FW_kDevice);
- bc.SetMapping (mapping);
- FW_CPlatformRect bounds (0, 0, cinfo.output_width, cinfo.output_height);
- FW_CRectShape::RenderRect (bc, bounds, FW_kFill, FW_kWhiteEraseInk);
- }
- int bytes = cinfo.output_width * cinfo.output_components;
- JOCTET** buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE, bytes, 1);
-
- // Prepare for decoding the samples
- short width, height, rowBytes, depth;
- bitmap.GetBitmapInfo (width, height, rowBytes, depth); // All I *want* is rowBytes
- FW_PlatformBitmap pb = bitmap.GetPlatformBitmap();
- PixMapHandle pm = ::GetGWorldPixMap (pb);
- Boolean locked = ::LockPixels (pm);
- TempMacLockedPixels unlock (pm);
- Ptr base = ::GetPixBaseAddr (pm);
-
- // Decode each row as it comes in. If we run ahead of the network, the sink object
- // will automatically sleep, so we never need to worry about suspension.
- while (cinfo.output_scanline < cinfo.output_height) {
- jpeg_read_scanlines (&cinfo, buffer, 1);
- ODF_JPEG_DecodeRow (buffer[0], bytes, base, rowBytes);
- base += rowBytes;
- }
-
- jpeg_finish_decompress(&cinfo);
- jpeg_destroy_decompress(&cinfo);
- }
- FW_CATCH_BEGIN
- FW_CATCH_EVERYTHING() {
- jpeg_destroy_decompress(&cinfo);
- FW_THROW_SAME();
- }
- FW_CATCH_END
-
- return bitmap;
- }
-
-